package com.foo.common.base.service;

import java.io.Serializable;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.stat.Statistics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.foo.common.base.dao.FooGenericDao;
import com.foo.common.base.pojo.FooGenericSearch;
import com.foo.common.base.pojo.FooGenericSearchResult;
import com.foo.common.base.pojo.FooGenericTransactionModel;
import com.google.common.collect.Lists;

@Service
@SuppressWarnings("unchecked")
@Transactional
public class FooGenericServiceImpl implements FooGenericService {

	@Autowired
	protected FooGenericDao fooGenericDao;

	protected Logger logger = LoggerFactory
			.getLogger(this.getClass().getName());

	@Override
	public Serializable save(Object entity) {
		return fooGenericDao.save(entity);
	}

	@Override
	public <T> void batchSave(List<T> entity) {
		fooGenericDao.batchSave(entity);
	}

	@Override
	public void update(Object entity) {
		fooGenericDao.update(entity);
	}

	@Override
	public void doInTransaction(
			FooGenericTransactionModel fooGenericTransactionModel) {
		Session session = fooGenericDao.getSession();
		Transaction tx = session.getTransaction();
		System.out.println(tx.getTimeout());
		// See:http://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html/ch13.html#transactions-demarcation-nonmanaged
		try {
			fooGenericTransactionModel.execute();
			// tx.setTimeout(200);
		} catch (RuntimeException e) {
			e.printStackTrace();
			throw e;
		} finally {
			// session.close();
		}
	}

	@Override
	public FooGenericSearchResult searchAndCount(
			FooGenericSearch fooGenericSearch) {
		Query query = fooGenericDao.getSession()
				.createQuery(fooGenericSearch.getQueryHql())
				.setCacheable(fooGenericSearch.isCacheable())
				.setCacheRegion(fooGenericSearch.getCacheRegion());
		query.setFirstResult(fooGenericSearch.getFirstResult());
		query.setMaxResults(fooGenericSearch.getMaxResults());
		FooGenericSearchResult myResult = new FooGenericSearchResult();
		myResult.setResult(query.list());
		query = fooGenericDao.getSession()
				.createQuery(fooGenericSearch.getCountHql())
				.setCacheable(fooGenericSearch.isCacheable())
				.setCacheRegion(fooGenericSearch.getCacheRegion());
		myResult.setTotalCount(((Integer) query.iterate().next()).intValue());
		return myResult;
	}

	@Override
	public void delete(Object object) {
		fooGenericDao.delete(object);

	}

	@Override
	public int executeHql(String hql) {
		Query query = fooGenericDao.getSession().createQuery(hql);
		return query.executeUpdate();
	}

	@Override
	public <T> T get(Class<T> clazz, Serializable id) {
		return (T) fooGenericDao.get(clazz, id);
	}

	@Override
	public void flush() {
		fooGenericDao.flush();
	}

	@Override
	public <T> void evictEntityRegion(Class<T> entityClass) {
		getSessionFactory().getCache().evictEntityRegion(entityClass);
	}

	@Override
	public <T> void evictQueryRegion(String regionName) {
		getSessionFactory().getCache().evictQueryRegion(regionName);
	}

	@Override
	public <T> List<T> list(FooGenericSearch fooGenericSearch) {
		Query query = fooGenericDao.getSession()
				.createQuery(fooGenericSearch.getQueryHql())
				.setFirstResult(fooGenericSearch.getFirstResult())
				.setMaxResults(fooGenericSearch.getMaxResults())
				.setCacheable(fooGenericSearch.isCacheable())
				.setCacheRegion(fooGenericSearch.getCacheRegion());

		List<T> myList = query.list();
		if (myList != null && myList.size() >= 1) {
			return query.list();
		}
		return Lists.newArrayList();
	}

	@Override
	public <T> List<T> list(String hql) {

		Query query = fooGenericDao.getSession().createQuery(hql);
		if (query.list() != null && query.list().size() >= 1) {
			return query.list();
		}
		return Lists.newArrayList();

	}

	@Override
	public SessionFactory getSessionFactory() {
		return fooGenericDao.getSession().getSessionFactory();
	}

	@Override
	public String logSummary() {
		Statistics stats = fooGenericDao.getSessionFactory().getStatistics();
		stats.logSummary();
		return stats.toString();
	}

	@Override
	public <T> T getObject(String hql) {
		Query query = fooGenericDao.getSession().createQuery(hql);
		query.setMaxResults(1);
		if (query.list() != null && query.list().size() >= 1) {
			return (T) query.list().get(0);
		}
		return null;
	}

	@Override
	public int count(String hql) {
		return ((Integer) fooGenericDao.getSession().createQuery(hql).iterate()
				.next()).intValue();
	}

	@Override
	public void saveOrUpdate(Object object) {
		fooGenericDao.saveOrUpdate(object);
	}

}
